﻿/*
Copyright (c) 2009 Vratislav Cermak (vratacermak@gmail.com)
 
This file is part of TeachMe Project. See http://code.google.com/p/teach-me for more information.
 
TeachMe is an open source project. Using of TeachMe is free of charge.
It is distributed under GNU General Public License version 3 (GPLv3).
GPLv3 can be found at http://www.gnu.org/licenses/gpl.html.
 
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE.  See the license for more details.
*/

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.IO;
using BrightIdeasSoftware;
using TeachMe.Application.Configuration;
using TeachMe.Application.Controls;
using TeachMe.Application.Data;
using TeachMe.Application.Events;
using TeachMe.Application.Exceptions;
using TeachMe.Application.Properties;
using TeachMe.Application.Themes;

namespace TeachMe.Application.Forms
{
    public partial class SettingsForm : PseudoModalForm
    {
        private readonly Root _root;
        private bool _themesReloadSuspended;
        private readonly List<EditedDictionaryDescriptor> _editedDicts = new List<EditedDictionaryDescriptor>();

        public SettingsForm(Root root)
        {
            _root = root;
            _root.UserSettings.CheckOut();
            _root.MachineSettings.CheckOut();
            _root.ImportExcludes.CheckOut();

            InitializeComponent();
            InitializeDictsTable();

            LoadDicts();
            LoadHotkeys();
            LoadGeneral();

            WindowProportions.Lock(this, _root.MachineSettings);
            ListViewColumnsProportions.Lock(this, lvDictionaries, _root.MachineSettings);

            tcMain.SelectedIndex = _root.MachineSettings.LastSettingsPageIndex;

            foreach (TrackBarLabel trackBarLabel in Utilities.GetControls<TrackBarLabel>(this))
            {
                trackBarLabel.UpdateText();
            }

            seOptionsForDisplayedEntriesCount.ErrorText = String.Format(Resources.InvalidNumberedOptionsValue, tbDisplayedEntriesCount.Minimum, tbDisplayedEntriesCount.Maximum);
            seOptionsForSuspendIntervals.ErrorText = String.Format(Resources.InvalidNumberedOptionsValue, 1, 120);
        }

        #region Hotkeys

        private void LoadHotkeys()
        {
            _root.HotkeysManager.UnregisterAll();

            Keys modifiers, key;

            if (_root.HotkeysManager.GetHotkey(HotkeyType.CreateEntry, out modifiers, out key))
            {
                heCreateEntryHotkey.Set(modifiers, key);
            }

            if (_root.HotkeysManager.GetHotkey(HotkeyType.DisplayEntry, out modifiers, out key))
            {
                heDisplayEntryHotkey.Set(modifiers, key);
            }

            if (_root.HotkeysManager.GetHotkey(HotkeyType.Suspend, out modifiers, out key))
            {
                heSuspendHotkey.Set(modifiers, key);
            }
        }

        private void SaveHotkeys()
        {
            Keys modifiers, key;

            if (heCreateEntryHotkey.Modified)
            {
                if (heCreateEntryHotkey.Get(out modifiers, out key))
                {
                    _root.HotkeysManager.SetHotkey(HotkeyType.CreateEntry, modifiers, key);
                }
                else
                {
                    _root.HotkeysManager.RemoveHotkey(HotkeyType.CreateEntry);
                }
            }

            if (heDisplayEntryHotkey.Modified)
            {
                if (heDisplayEntryHotkey.Get(out modifiers, out key))
                {
                    _root.HotkeysManager.SetHotkey(HotkeyType.DisplayEntry, modifiers, key);
                }
                else
                {
                    _root.HotkeysManager.RemoveHotkey(HotkeyType.DisplayEntry);
                }
            }

            if (heSuspendHotkey.Modified)
            {
                if (heSuspendHotkey.Get(out modifiers, out key))
                {
                    _root.HotkeysManager.SetHotkey(HotkeyType.Suspend, modifiers, key);
                }
                else
                {
                    _root.HotkeysManager.RemoveHotkey(HotkeyType.Suspend);
                }
            }
        }

        private bool AreHotkeysModified()
        {
            return heSuspendHotkey.Modified || heCreateEntryHotkey.Modified || heDisplayEntryHotkey.Modified;
        }

        #endregion

        #region Dicts

        private void SaveDicts()
        {
            foreach (EditedDictionaryDescriptor descriptor in _editedDicts)
            {
                switch (descriptor.State)
                {
                    case EditedItemState.New:
                    case EditedItemState.Normal:
                        if (descriptor.IsModified())
                        {
                            descriptor.Dictionary.UpdateUserSettings(descriptor.Enabled, descriptor.EntryTextDirection, descriptor.Priority);
                        }
                        break;
                    case EditedItemState.Deleted:
                        _root.RemoveDictionary(descriptor.Dictionary);
                        break;
                    default:
                        throw new ArgumentOutOfRangeException();
                }
            }
        }

        private void LoadDicts()
        {
            _editedDicts.Clear();

            foreach (Dictionary dictionary in _root.Dictionaries)
            {
                _editedDicts.Add(EditedDictionaryDescriptor.Create(dictionary));
            }

            UpdateDicts();
        }

        private void InitializeDictsTable()
        {
            ObjectListView.EditorRegistry.Register(typeof(EntryTextDirection), typeof(DirectionComboBox));
            ObjectListView.EditorRegistry.Register(typeof(Priority), typeof(PriorityComboBox));

            // let height be like combo
            lvDictionaries.RowHeight = new ComboBox().Height;

            InitPriorityColumn();
            InitDirectionColumn();
        }

        private void InitDirectionColumn()
        {
            colDirection.AspectType = typeof(EntryTextDirection);

            colDirection.AspectGetter += delegate(object rowObject)
                                             {
                                                 EditedDictionaryDescriptor descriptor = rowObject as EditedDictionaryDescriptor;
                                                 if (descriptor == null)
                                                 {
                                                     throw new InvalidOperationException();
                                                 }
                                                 switch (descriptor.EntryTextDirection)
                                                 {
                                                     case EntryTextDirection.FromTo:
                                                         return String.Format(Resources.OneDirection, descriptor.Dictionary.Entries.From, descriptor.Dictionary.Entries.To);
                                                     case EntryTextDirection.ToFrom:
                                                         return String.Format(Resources.OneDirection, descriptor.Dictionary.Entries.To, descriptor.Dictionary.Entries.From);
                                                     case EntryTextDirection.Both:
                                                         return String.Format(Resources.BothDirections, descriptor.Dictionary.Entries.From, descriptor.Dictionary.Entries.To);
                                                     default:
                                                         throw new ArgumentOutOfRangeException();
                                                 }
                                             };

            colDirection.AspectPutter += delegate
                                             {
                                                 // ignored
                                             };
        }

        private void InitPriorityColumn()
        {
            colPriority.AspectType = typeof(Priority);

            colPriority.AspectGetter += delegate(object rowObject)
                                            {
                                                EditedDictionaryDescriptor descriptor = rowObject as EditedDictionaryDescriptor;
                                                if (descriptor == null)
                                                {
                                                    throw new InvalidOperationException();
                                                }
                                                switch (descriptor.Priority)
                                                {
                                                    case Priority.VeryLow:
                                                        return Resources.VeryLowPriority;
                                                    case Priority.Low:
                                                        return Resources.LowPriority;
                                                    case Priority.Normal:
                                                        return Resources.NormalPriority;
                                                    case Priority.High:
                                                        return Resources.HighPriority;
                                                    default:
                                                        throw new ArgumentOutOfRangeException();
                                                }
                                            };

            colPriority.AspectPutter += delegate
                                            {
                                                // ignored
                                            };
        }

        private void OnCellDictsEditStarting(object sender, CellEditEventArgs e)
        {
            EditedDictionaryDescriptor descriptor = e.RowObject as EditedDictionaryDescriptor;
            if (descriptor == null)
            {
                throw new InvalidOperationException();
            }

            if (e.Column == colDirection)
            {
                DirectionComboBox comboBox = e.Control as DirectionComboBox;
                if (comboBox == null)
                {
                    throw new InvalidOperationException();
                }

                comboBox.FillDirections(descriptor.Dictionary.Entries.From, descriptor.Dictionary.Entries.To);
                comboBox.EntryTextDirection = descriptor.EntryTextDirection;
            }
            else if (e.Column == colPriority)
            {
                PriorityComboBox comboBox = e.Control as PriorityComboBox;
                if (comboBox == null)
                {
                    throw new InvalidOperationException();
                }

                comboBox.FillPriorities(Priority.Low, Priority.Normal, Priority.High);
                comboBox.Priority = descriptor.Priority;
            }
        }

        private void OnCellDictsEditFinishing(object sender, CellEditEventArgs e)
        {
            EditedDictionaryDescriptor descriptor = e.RowObject as EditedDictionaryDescriptor;
            if (descriptor == null)
            {
                throw new InvalidOperationException();
            }

            if (e.Column == colDirection)
            {
                DirectionComboBox comboBox = e.Control as DirectionComboBox;
                if (comboBox == null)
                {
                    throw new InvalidOperationException();
                }

                if (!comboBox.OneWay)
                {
                    descriptor.EntryTextDirection = comboBox.EntryTextDirection;
                }
            }
            else if (e.Column == colPriority)
            {
                PriorityComboBox comboBox = e.Control as PriorityComboBox;
                if (comboBox == null)
                {
                    throw new InvalidOperationException();
                }
                
                descriptor.Priority = comboBox.Priority;
            }
        }

        private IEnumerable<EditedDictionaryDescriptor> GetEditedDicts()
        {
            foreach (EditedDictionaryDescriptor descriptor in _editedDicts)
            {
                if (descriptor.State != EditedItemState.Deleted)
                {
                    yield return descriptor;
                }
            }
        }

        private void UpdateDicts()
        {
            lvDictionaries.SetObjects(GetEditedDicts());

            UpdateDictsToolbar();
        }

        private void OnAddDictButtonClick(object sender, EventArgs e)
        {
            if (Directory.Exists(_root.MachineSettings.LastBrowseDirectory))
            {
                dlgAddDictionary.InitialDirectory = _root.MachineSettings.LastBrowseDirectory;
            }

            if (dlgAddDictionary.ShowDialog() == DialogResult.OK)
            {
                using (_root.MachineSettings.Edit())
                {
                    _root.MachineSettings.LastBrowseDirectory = Path.GetDirectoryName(dlgAddDictionary.FileName);
                }

                foreach (string path in dlgAddDictionary.FileNames)
                {
                    bool alreadyUsed = false;

                    foreach (Dictionary dict in GetActiveDicts())
                    {
                        if (String.Compare(dict.UserData.Path, path, true) == 0)
                        {
                            MessageBox.Show(String.Format(Resources.DictionaryAlreadyUsed, dlgAddDictionary.FileName), Resources.MessageBoxCaption, MessageBoxButtons.OK, MessageBoxIcon.Stop);

                            alreadyUsed = true;
                        }
                    }

                    if (!alreadyUsed)
                    {
                        Dictionary dictionary = null;

                        try
                        {
                            dictionary = _root.AddNewDictionary(path);
                        }
                        catch(DictionaryException exception)
                        {
                            Logging.Error(GetType(), exception, "Dictionary could not be created.");

                            MessageBox.Show(Resources.DictionaryCreateError, Resources.MessageBoxCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
                        }

                        if (dictionary != null)
                        {
                            EditedDictionaryDescriptor descriptor = EditedDictionaryDescriptor.CreateNew(dictionary);

                            lvDictionaries.AddObject(descriptor);
                            _editedDicts.Add(descriptor);
                        }
                    }
                }
            }
        }

        private List<Dictionary> GetActiveDicts()
        {
            List<Dictionary> result = new List<Dictionary>();

            foreach (EditedDictionaryDescriptor descriptor in _editedDicts)
            {
                if (descriptor.State != EditedItemState.Deleted)
                {
                    result.Add(descriptor.Dictionary);
                }
            }

            return result;
        }

        private void OnRemoveDictsButtonClick(object sender, EventArgs e)
        {
            RemoveSelectedDicts();
        }

        private void RemoveSelectedDicts()
        {
            foreach (EditedDictionaryDescriptor descriptor in lvDictionaries.SelectedObjects)
            {
                if (descriptor.State == EditedItemState.New)
                {
                    _root.RemoveDictionary(descriptor.Dictionary);
                    _editedDicts.Remove(descriptor);
                }
                else
                {
                    descriptor.State = EditedItemState.Deleted;
                }
            }

            lvDictionaries.RemoveObjects(lvDictionaries.SelectedObjects);
        }

        private void OnRefreshDictsButtonClick(object sender, EventArgs e)
        {
            RefreshSelectedDicts();
        }

        private void RefreshSelectedDicts()
        {
            bool failed = false;

            foreach (EditedDictionaryDescriptor descriptor in lvDictionaries.SelectedObjects)
            {
                try
                {
                    _root.RefreshDictionary(descriptor.Dictionary);
                }
                catch (DictionaryException exception)
                {
                    Logging.Error(GetType(), exception, "Dictionary could not be refreshed.");

                    failed = true;
                }
            }

            if (failed)
            {
                MessageBox.Show(Resources.DictionaryRefreshError, Resources.MessageBoxCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);
            }

            lvDictionaries.RefreshObjects(lvDictionaries.SelectedObjects);
        }

        private void OnDictionaryContextMenuOpening(object sender, CancelEventArgs e)
        {
            cmiEditDict.Enabled = lvDictionaries.SelectedItems.Count == 1;
            cmiRefreshDict.Enabled = lvDictionaries.SelectedItems.Count > 0;
            cmiRemoveDict.Enabled = lvDictionaries.SelectedItems.Count > 0;
        }

        private void OnContextMenuDictsRefreshClick(object sender, EventArgs e)
        {
            RefreshSelectedDicts();
        }

        private void OnContextMenuDictsRemoveClick(object sender, EventArgs e)
        {
            RemoveSelectedDicts();
        }

        private void OnSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e)
        {
            UpdateDictsToolbar();
        }

        private void UpdateDictsToolbar()
        {
            tsbRemoveDicts.Enabled = lvDictionaries.SelectedItems.Count > 0;
            tsbRefreshDicts.Enabled = lvDictionaries.SelectedItems.Count > 0;
            tsbEditDicts.Enabled = lvDictionaries.SelectedItems.Count == 1;
        }

        private void OnCreateDictButtonClick(object sender, EventArgs e)
        {
            EntriesEditorForm entriesEditorForm = new EntriesEditorForm(_root, GetActiveDicts());

            entriesEditorForm.PseudoParent = this;
            entriesEditorForm.Show();
            entriesEditorForm.Closed += delegate
                                            {
                                                if (entriesEditorForm.CreatedDictionary != null)
                                                {
                                                    _editedDicts.Add(EditedDictionaryDescriptor.CreateNew(entriesEditorForm.CreatedDictionary));
                                                }

                                                UpdateDicts();
                                            };
        }

        private void OnEditSelectedDict(object sender, EventArgs e)
        {
            EditSelectedDict();
        }

        private void OnContextMenuEditEntries(object sender, EventArgs e)
        {
            EditSelectedDict();
        }

        private void EditSelectedDict()
        {
            EditedDictionaryDescriptor descriptor = lvDictionaries.SelectedObject as EditedDictionaryDescriptor;
            if (descriptor == null)
            {
                throw new InvalidOperationException();
            }

            EntriesEditorForm form = new EntriesEditorForm(_root, GetActiveDicts(), descriptor.Dictionary);
            _root.FormsManager.Add(form);
            form.PseudoParent = this;
            form.Show();
            form.Closed += delegate
                               {
                                   try
                                   {
                                       UpdateDicts();

                                       tbImportExcludes.Text = _root.ImportExcludes.Words.Value;
                                   }
                                   finally
                                   {
                                       _root.FormsManager.Remove(form);
                                   }
                               };
        }

        private void OnDictsDoubleClick(object sender, EventArgs e)
        {
            if (lvDictionaries.SelectedObjects.Count == 1)
            {
                EditSelectedDict();
            }
        }

        private void RevertDicts()
        {
            foreach (EditedDictionaryDescriptor descriptor in _editedDicts)
            {
                if (descriptor.State == EditedItemState.New)
                {
                    _root.RemoveDictionary(descriptor.Dictionary);
                }
            }
        }

        private bool AreDictsModified()
        {
            foreach (EditedDictionaryDescriptor descriptor in _editedDicts)
            {
                switch (descriptor.State)
                {
                    case EditedItemState.Normal:
                        if (descriptor.IsModified())
                        {
                            return true;
                        }
                        break;
                    case EditedItemState.Deleted:
                        return true;
                    case EditedItemState.New:
                        return true;
                    default:
                        throw new ArgumentOutOfRangeException();
                }
            }

            return false;
        }

        #endregion

        #region Themes
        
        private void LoadThemes(string directory)
        {
            if (_themesReloadSuspended)
            {
                return;
            }

            lbThemes.Items.Clear();

            lbThemes.Items.Add(Resources.DefaultThemeName);

            if (Directory.Exists(directory))
            {
                Logging.Debug(GetType(), "Loading themes from directory '{0}'", directory);

                string[] files = Directory.GetFiles(directory, "*.tme", SearchOption.AllDirectories);

                foreach (string file in files)
                {
                    Logging.Debug(GetType(), "Loading theme '{0}'", file);

                    Theme theme;

                    try
                    {
                        theme = ThemeLoader.LoadFromArchive(_root.TemporaryContentManager, file);
                    }
                    catch (Exception e)
                    {
                        Logging.Error(GetType(), e, "Theme '{0}' could not be loaded.", file);

                        continue;
                    }

                    lbThemes.Items.Add(theme);
                }
            }
        }

        private void OnSelectedThemeChanged(object sender, EventArgs e)
        {
            Theme theme = lbThemes.SelectedItem as Theme;
            _root.UserSettings.CurrentThemePath = theme != null ? theme.Path : null;
        }

        private void OnThemesDirectoryTextChanged(object sender, EventArgs e)
        {
            _root.UserSettings.ThemesDirectory = tbThemesDirectory.Text;
        }

        private void OnSelectThemesDirectoryClick(object sender, EventArgs e)
        {
            if (Directory.Exists(_root.UserSettings.ThemesDirectory))
            {
                dlgThemesFolder.SelectedPath = _root.UserSettings.ThemesDirectory;
            }

            if (dlgThemesFolder.ShowDialog(this) == DialogResult.OK)
            {
                tbThemesDirectory.Text = dlgThemesFolder.SelectedPath;
                _root.UserSettings.ThemesDirectory = dlgThemesFolder.SelectedPath;
            }
        }

        private void OnPopulateThemesClick(object sender, EventArgs e)
        {
            LoadThemes(tbThemesDirectory.Text);
        }

        #endregion

        #region General

        private void LoadGeneral()
        {
            switch (_root.UserSettings.NewEntryMode.Value)
            {
                case NewEntryMode.Persistent:
                    rbNewEntryModePersistent.Checked = true;
                    break;
                case NewEntryMode.Interval:
                    rbNewEntryModeInterval.Checked = true;
                    break;
                case NewEntryMode.OnDemand:
                    rbNewEntryModeOnDemand.Checked = true;
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }

            switch (_root.UserSettings.EntryRevealReason.Value)
            {
                case EntryRevealReason.Immediate:
                    rbEntryRevealModeImmediate.Checked = true;
                    break;
                case EntryRevealReason.Click:
                    rblEntryRevealModeClick.Checked = true;
                    break;
                case EntryRevealReason.Interval:
                    rbEntryRevealModeInterval.Checked = true;
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }

            cbEntriesAlwaysOnTop.Checked = _root.UserSettings.TopMostEntries.Value;
            
            tbHintInterval.Value = _root.UserSettings.HintInterval.Value;
            tbNewEntryInterval.Value = _root.UserSettings.NewEntryInterval.Value;
            tbNewEntryIntervalInTurboMode.Value = _root.UserSettings.TurboModeInterval.Value;
            
            tbDisplayedEntriesCount.Value = _root.UserSettings.MaxEntriesNumber.Value;
            seOptionsForDisplayedEntriesCount.Text = _root.UserSettings.MaxEntriesNumbers.Value;

            tbEntryOpacity.Value = _root.UserSettings.EntryOpacity.Value;
            tbHorizontalDistance.Value = _root.UserSettings.EntriesHorizontalDistance.Value;
            tbVerticalDistance.Value = _root.UserSettings.EntriesVerticalDistance.Value;

            tbVeryLowPriority.Value = _root.UserSettings.VeryLowPriorityRate.Value;
            tbLowPriority.Value = _root.UserSettings.LowPriorityRate.Value;
            tbNormalPriority.Value = _root.UserSettings.NormalPriorityRate.Value;
            tbHighPriority.Value = _root.UserSettings.HighPriorityRate.Value;

            tbHotkeySuspendInterval.Value = _root.UserSettings.HotkeySuspendInterval.Value;
            seOptionsForSuspendIntervals.Text = _root.UserSettings.SuspendIntervals.Value;

            tbImportExcludes.Text = _root.ImportExcludes.Words.Value;
            tbMinimalWordLen.Value = _root.UserSettings.MinImportedWordLen.Value;
            cbUseRegExForExcludedWords.Checked = _root.UserSettings.UseRegExForExcludedWords.Value;

            cbNewVersionCheckInterval.FillIntervals();
            cbNewVersionCheckInterval.Interval = _root.UserSettings.NewVersionCheckInterval.Value;

            //

            foreach (EncodingInfo encodingInfo in Encoding.GetEncodings())
            {
                cbImportFileCodepage.Items.Add(encodingInfo.GetEncoding().HeaderName);
            }

            Encoding encoding = Encoding.GetEncoding(_root.UserSettings.ImportEncoding.Value);

            if (encoding != null)
            {
                cbImportFileCodepage.Text = encoding.HeaderName;
            }

            //

            try
            {
                _themesReloadSuspended = true;

                tbThemesDirectory.Text = _root.UserSettings.ThemesDirectory;
            }
            finally
            {
                _themesReloadSuspended = false;
            }

            cbAutoStart.Checked = _root.AutoStart;

            ComboBoxItem<CultureInfo> selection = null;

            foreach (string supportedCulture in _root.SupportedCultures)
            {
                CultureInfo cultureInfo;
                
                try
                {
                    cultureInfo = CultureInfo.GetCultureInfo(supportedCulture);
                }
                catch(Exception e)
                {
                    Logging.Error(GetType(), e, "Cannot get culture info for '{0}'.", supportedCulture);

                    continue;
                }

                ComboBoxItem<CultureInfo> item = new ComboBoxItem<CultureInfo>(cultureInfo, cultureInfo.NativeName.ToLower(cultureInfo));

                if (cultureInfo.Equals(Thread.CurrentThread.CurrentUICulture))
                {
                    selection = item;   
                }

                cbLanguages.Items.Add(item);
            }

            cbLanguages.SelectedItem = selection;
        }

        private NewEntryMode GetNewEntryMode()
        {
            if (rbNewEntryModePersistent.Checked)
            {
                return NewEntryMode.Persistent;
            }
            if (rbNewEntryModeOnDemand.Checked)
            {
                return NewEntryMode.OnDemand;
            }
            if (rbNewEntryModeInterval.Checked)
            {
                return NewEntryMode.Interval;
            }
            throw new ArgumentOutOfRangeException();
        }

        private EntryRevealReason GetEntryRevealReason()
        {
            if (rblEntryRevealModeClick.Checked)
            {
                return EntryRevealReason.Click;
            }
            if (rbEntryRevealModeInterval.Checked)
            {
                return EntryRevealReason.Interval;
            }
            if (rbEntryRevealModeImmediate.Checked)
            {
                return EntryRevealReason.Immediate;
            }
            throw new ArgumentOutOfRangeException();
        }

        private void OnEntryOpacityChanged(object sender, EventArgs e)
        {
            _root.UserSettings.EntryOpacity.Value = (byte)tbEntryOpacity.Value;
        }

        private void OnHorizontalDistanceChanged(object sender, EventArgs e)
        {
            _root.UserSettings.EntriesHorizontalDistance.Value = tbHorizontalDistance.Value;
        }

        private void OnVerticalDistanceChanged(object sender, EventArgs e)
        {
            _root.UserSettings.EntriesVerticalDistance.Value = tbVerticalDistance.Value;
        }

        private void OnTopMostEntriesChanged(object sender, EventArgs e)
        {
            _root.UserSettings.TopMostEntries.Value = cbEntriesAlwaysOnTop.Checked;
        }

        private void OnNewEntryModeChanged(object sender, EventArgs e)
        {
            bool enable = !rbNewEntryModeOnDemand.Checked;

            txNewEntryInterval.Enabled = enable;
            tbNewEntryInterval.Enabled = enable;
            txNewEntryIntervalValue.Enabled = enable;
            txNewEntryIntervalInTurboMode.Enabled = enable;
            tbNewEntryIntervalInTurboMode.Enabled = enable;
            txNewEntryIntervalInTurboModeValue.Enabled = enable;
        }

        private void OnEntryRevealModeChanged(object sender, EventArgs e)
        {
            txHintInterval.Enabled = rbEntryRevealModeInterval.Checked;
            tbHintInterval.Enabled = rbEntryRevealModeInterval.Checked;
            txHintIntervalValue.Enabled = rbEntryRevealModeInterval.Checked;
        }

        private void OnSelectedLanguageChanged(object sender, EventArgs e)
        {
            //
        }

        private void SaveGeneral()
        {
            if (_root.UserSettings.EntryRevealReason.Value != GetEntryRevealReason())
            {
                _root.UserSettings.EntryRevealReason.Value = GetEntryRevealReason();
            }

            if (_root.UserSettings.NewEntryMode.Value != GetNewEntryMode())
            {
                _root.UserSettings.NewEntryMode.Value = GetNewEntryMode();
            }

            if (tbNewEntryInterval.Value != _root.UserSettings.NewEntryInterval.Value)
            {
                _root.UserSettings.NewEntryInterval.Value = tbNewEntryInterval.Value;
            }

            if (_root.UserSettings.TurboModeInterval.Value != tbNewEntryIntervalInTurboMode.Value)
            {
                _root.UserSettings.TurboModeInterval.Value = tbNewEntryIntervalInTurboMode.Value;
            }

            if (_root.UserSettings.MaxEntriesNumber.Value != tbDisplayedEntriesCount.Value)
            {
                _root.UserSettings.MaxEntriesNumber.Value = tbDisplayedEntriesCount.Value;
            }

            if (_root.UserSettings.MaxEntriesNumbers.Value != seOptionsForDisplayedEntriesCount.Text)
            {
                _root.UserSettings.MaxEntriesNumbers.Value = seOptionsForDisplayedEntriesCount.Text;
            }

            if (_root.UserSettings.HotkeySuspendInterval.Value != tbHotkeySuspendInterval.Value)
            {
                _root.UserSettings.HotkeySuspendInterval.Value = tbHotkeySuspendInterval.Value;
            }

            if (_root.UserSettings.SuspendIntervals.Value != seOptionsForSuspendIntervals.Text)
            {
                _root.UserSettings.SuspendIntervals.Value = seOptionsForSuspendIntervals.Text;
            }

            if (_root.UserSettings.VeryLowPriorityRate.Value != tbVeryLowPriority.Value)
            {
                _root.UserSettings.VeryLowPriorityRate.Value = tbVeryLowPriority.Value;
            }

            if (_root.UserSettings.LowPriorityRate.Value != tbLowPriority.Value)
            {
                _root.UserSettings.LowPriorityRate.Value = tbLowPriority.Value;
            }

            if (_root.UserSettings.NormalPriorityRate.Value != tbNormalPriority.Value)
            {
                _root.UserSettings.NormalPriorityRate.Value = tbNormalPriority.Value;
            }

            if (_root.UserSettings.HighPriorityRate.Value != tbHighPriority.Value)
            {
                _root.UserSettings.HighPriorityRate.Value = tbHighPriority.Value;
            }

            if (cbAutoStart.Checked != _root.AutoStart)
            {
                _root.AutoStart = cbAutoStart.Checked;
            }

            if (cbNewVersionCheckInterval.Interval != _root.UserSettings.NewVersionCheckInterval.Value)
            {
                _root.UserSettings.NewVersionCheckInterval.Value = cbNewVersionCheckInterval.Interval;
            }

            //

            if (cbLanguages.SelectedItem != null)
            {
                ComboBoxItem<CultureInfo> value = cbLanguages.SelectedItem as ComboBoxItem<CultureInfo>;
                if (value == null)
                {
                    throw new InvalidOperationException();
                }
                _root.UserSettings.Language.Value = value.Item.Name;
            }
        }

        private void OnValidatingOptionsForSuspendIntervals(object sender, ValidatingEventArgs e)
        {
            if (!ValidateOptions(seOptionsForSuspendIntervals.Text, 1, 120))
            {
                e.Valid = false;
            }
        }

        private void OnValidatingOptionsForDisplayedEntriesCount(object sender, ValidatingEventArgs e)
        {
            if (!ValidateOptions(seOptionsForDisplayedEntriesCount.Text, tbDisplayedEntriesCount.Minimum, tbDisplayedEntriesCount.Maximum))
            {
                e.Valid = false;
            }
        }

        private void OnExcludeWordsLeave(object sender, EventArgs e)
        {
            _root.ImportExcludes.Words.Value = tbImportExcludes.Text;
        }

        private void OnImportCodepageLeave(object sender, EventArgs e)
        {
            _root.UserSettings.ImportEncoding.Value = cbImportFileCodepage.Text;
        }

        private void OnMinWordLenChanged(object sender, EventArgs e)
        {
            _root.UserSettings.MinImportedWordLen.Value = tbMinimalWordLen.Value;
        }

        private void OnUseRegExForExcludedWordsCheckChanged(object sender, EventArgs e)
        {
            _root.UserSettings.UseRegExForExcludedWords.Value = cbUseRegExForExcludedWords.Checked;
        }

        #endregion

        private void OnFormClosing(object sender, FormClosingEventArgs e)
        {
            if (DialogResult == DialogResult.Cancel)
            {
                if (AreDictsModified())
                {
                    RevertDicts();
                }

                _root.UserSettings.Revert();
                _root.ImportExcludes.Revert();

                return;
            }

            if (!IsContentValid())
            {
                MessageBox.Show(Resources.SettingsInvalidContent, Resources.MessageBoxCaption, MessageBoxButtons.OK, MessageBoxIcon.Error);

                e.Cancel = true;
                return;
            }

            if (AreDictsModified())
            {
                SaveDicts();
            }

            if (AreHotkeysModified())
            {
                SaveHotkeys();
            }

            SaveGeneral();

            _root.UserSettings.CheckIn();
            _root.ImportExcludes.CheckIn();
        }

        private void OnFormClosed(object sender, FormClosedEventArgs e)
        {
            _root.HotkeysManager.RegisterAll();

            _root.MachineSettings.LastSettingsPageIndex = tcMain.SelectedIndex;
            _root.MachineSettings.CheckIn();
        }

        private bool IsContentValid()
        {
            foreach (StrictEdit strictEdit in Utilities.GetControls<StrictEdit>(this))
            {
                if (!strictEdit.IsValid())
                {
                    return false;
                }
            }

            return true;
        }

        private static bool ValidateOptions(string text, int min, int max)
        {
            if (String.IsNullOrEmpty(text))
            {
                return false;
            }
            string[] parts = text.Split(new []{';'}, StringSplitOptions.RemoveEmptyEntries);

            if (parts.Length == 0)
            {
                return false;
            }
            foreach (string part in parts)
            {
                int number;
                if (!Int32.TryParse(part, out number))
                {
                    return false;
                }
                if (number < min || number > max)
                {
                    return false;
                }
            }

            return true;
        }

        private void OnHintIntervalChanged(object sender, EventArgs e)
        {
            _root.UserSettings.HintInterval.Value = tbHintInterval.Value;
        }
    }
}
